Skip to content

Getting Started

Before we get to the dazzling layout animation stuff, I think it'll help if we start with a “Hello World” example. Let's talk about how to slide a DOM node around.

Video Summary

So our goal is to move a yellow ball whenever we click the button:

Here's the setup we're working with:

import React from 'react';
function App() {
const [isEnabled, setIsEnabled] = React.useState(false);
return (
<>
<div className="yellow ball" />
<button onClick={() => setIsEnabled(!isEnabled)}>
Toggle
</button>
</>
);
}
export default App;

When isEnabled is true, I want to move the ball down by 60 pixels.

The first step is to import the motion utility:

import { motion } from 'framer-motion';

Then, we need to swap out the element we wish to animate with its motion counterpart. Instead of rendering a <div>, we'll render a <motion.div>:

<motion.div className="yellow ball" />

motion.div is a component that wraps around a primitive <div>. It does everything a <div> can do, and it'll forward along any attributes I set.

motion can wrap around any HTML tag. If I render a <motion.button>, it'll produce an HTML <button>.

Framer Motion wrapper components give us a couple of new super-powers. We can apply an animation with the animate prop:

In our case, we want the ball to move up and down based on the isEnabled prop, and so we'll structure it like this:

<motion.div
className="example"
animate={{
y: isEnabled ? 0 : 60,
}}
/>

When isEnabled is false, the ball moves down by 60px. Specifically, it'll apply a CSS transform, translateY(60px).

By default, Framer Motion uses spring physics. This produces much more fluid, life-like animation compared to the Bézier curves we get with CSS transitions. The default animation is quite nice, but it's very springy, which might not be what we want.

We can customize it using the transition property. For example, here's how we set it up to use a Bézier curve:

<motion.div
className="example"
transition={{
type: 'tween',
ease: 'easeInOut',
}}
animate={{
y: isEnabled ? 0 : 60,
}}
/>

Instead, though, I strongly recommend sticking with spring physics. We can customize the transition using the stiffness and damping properties:

<motion.div
className="example"
transition={{
type: 'spring',
stiffness: 200,
damping: 25,
}}
animate={{
y: isEnabled ? 0 : 60,
}}
/>

I realize these numbers probably seem totally random; you can start building an intuition for how spring physics work in my blog post, A Friendly Introduction to Spring Physics.

But yeah, we're just about done our “Hello World” implementation. There's just one more thing to mention.

When the page first loads, our yellow ball slides down:

This is because the animate prop includes an enter animation out-of-the-box. It animates to the initially-specified value.

In many situations, this is actually a good thing, but it won't always be what we want. We can disable this with the initial prop:

<motion.div
initial={false}
className="example"
transition={{
type: 'tween',
ease: 'easeInOut',
}}
animate={{
y: isEnabled ? 0 : 60,
}}
/>

This is the typical flow with Framer Motion! We import our motion utility, swap out the DOM node(s) we want to animate for their motion.x counterparts, tweak the transition with the transition prop, and customize the animation. The animate prop is used when we have specific values, or we can use the layout prop, which will be discussed shortly.

You can start building an intuition for how spring physics work with my blog post, A Friendly Introduction to Spring Physics. You can also learn more about the stuff we covered in the Framer Motion docs.

Here's the final code from the video above:

Code Playground

import React from 'react';
import { motion } from 'framer-motion';

function App() {
const [isEnabled, setIsEnabled] = React.useState(true);
return (
<>
<motion.div
initial={false}
className="yellow ball"
transition={{
type: 'spring',
stiffness: 200,
damping: 25,
}}
animate={{
y: isEnabled ? 60 : 0,
}}
/>
<button onClick={() => setIsEnabled(!isEnabled)}>
Toggle
</button>
</>
);
}

export default App;